home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Cream of the Crop 1
/
Cream of the Crop 1.iso
/
COMM
/
MSKRMSRC.ARJ
/
MSNTNI.ASM
< prev
next >
Wrap
Assembly Source File
|
1991-10-24
|
18KB
|
707 lines
NAME MSNTNI
; File MSNTNI.ASM
; Telnet interface to MS-DOS Kermit
;
; Copyright (C) 1991, Trustees of Columbia University in the
; City of New York. Permission is granted to any individual or
; institution to use, copy, or redistribute this software as long as
; it is not sold for profit and this copyright notice is retained.
;
; Written by Joe R. Doupnik, Utah State University,
; jrd@cc.usu.edu, jrd@usu.Bitnet.
;
; Edit history
; 6 Sept 1991 version 3.11
; Last edit 16 Sept 1991
include mssdef.h
getintv equ 35h ; DOS get interrupt vector to es:bx
bapicon equ 0a0h ; 3Com BAPI, connect to port
bapidisc equ 0a1h ; 3Com BAPI, disconnect
bapiwrit equ 0a4h ; 3Com BAPI, write block
bapiread equ 0a5h ; 3Com BAPI, read block
bapibrk equ 0a6h ; 3Com BAPI, send short break
bapistat equ 0a7h ; 3Com BAPI, read status (# chars to be read)
bapihere equ 0afh ; 3Com BAPI, presence check
bapieecm equ 0b0h ; 3Com BAPI, enable/disable ECM char
bapiecm equ 0b1h ; 3Com BAPI, trap Enter Command Mode char
data segment public 'kdata'
extrn tcptos:word ; top of stack for TCP code
extrn flags:byte, yflags:byte, portval:word
data ends
_TEXT SEGMENT WORD PUBLIC 'CODE'
_TEXT ENDS
_DATA SEGMENT WORD PUBLIC 'DATA'
_DATA ENDS
CONST SEGMENT WORD PUBLIC 'CONST'
CONST ENDS
_BSS SEGMENT WORD PUBLIC 'BSS'
_BSS ENDS
DGROUP GROUP CONST, _BSS, _DATA
ASSUME CS: _TEXT, DS: DGROUP, SS: DGROUP
_DATA SEGMENT
public _kmyip, _knetmask, _kdomain, _kgateway, _kns1, _kns2, _khost
public _kbcast, _bapibuf, _bapireq, _bapiret, _msgcnt, _msgbuf
public _display_mode
extrn _my_ip_addr:dword, _sin_mask:dword
db 'DUMMY' ; null pointer guard
_kmyip db 33 dup (0) ; our IP number
_knetmask db 33 dup (0) ; our netmask
_kdomain db 33 dup (0) ; our domain
_kgateway db 33 dup (0) ; our gateway
_kns1 db 33 dup (0) ; our nameserver #1
_kns2 db 33 dup (0) ; our nameserver #2
_khost db 33 dup (0) ; remote host name/IP #
_kbcast db 33 dup (0) ; broadcast IP
_kserver dw 0 ; non-zero for Kermit server
bpprefix db 'Bootp ',0 ; prefix for Bootp provided IP addr
oldint14 dd 0 ; original Int 14h owner
oldint8 dd 0 ; original Int 8 owner
tcpstack dd 0 ; TCP code stack
stack8 dd 0 ; stack at Int 8 invokation
kstack dw 0 ; Kermit mainline stack pointer
tempax dw 0 ; a temp
tcpflag db 0 ; who is running TCP code: 1=Kermit, 2=Int 8
tcpdata dw 0 ; Kermit offset of "tcpdata" block
int8cnt db 0 ; Int 8 times called counter
_display_mode db 0 ; msg, none if == 0
opcode db 0 ; BAPI op code
userbuf dd 0 ; BAPI user's comms buffer address
_bapireq dw 0 ; BAPI count of chars requested
_bapiret dw 0 ; BAPI count of chars processed
buflen equ 512
_bapibuf db buflen dup (0) ; BAPI buffer in TCP address space
_msgcnt dw 0 ; count of bytes in msg buffer
_msgbuf db 256 dup (0) ; interrupt level msg buffer
_DATA ENDS
_TEXT segment
ASSUME CS: _TEXT, DS: DGROUP, SS: DGROUP
extrn _int14handler:near, _main:near, _exit:near, _pkt_release:near
extrn _int8tick:near, _bcopy:near, _itoa:near, _strlen:near
extrn _strcpy:near
public _enable
enable proc near
_enable equ this byte
sti
ret
enable endp
public _disable
disable proc near
_disable equ this byte
cli
ret
disable endp
; Hook Interrupts 8h and 14h. Return AX = 1 if successful else 0.
public _hookvect
hookvect proc near
_hookvect equ this byte
push bp
mov bp,sp
mov ax,bp
add ax,2+2 ; C sp just before this call
mov word ptr tcpstack,ax ; save as main prog stack level
push es
mov ah,getintv ; get interrupt vector
mov al,14h ; vector number
int dos
mov ax,es
mov cx,cs
cmp ax,cx ; points to us now?
je hook1 ; yes, don't touch again
mov word ptr DGROUP:oldint14+2,ax ; save segment
mov word ptr DGROUP:oldint14,bx ; save offset
mov dx,offset ourserial ; new handler
push ds
mov ax,cs ; segment
mov ds,ax
mov al,14h ; for Int 14h
mov ah,25H ; set interrupt address from ds:dx
int dos
pop ds
hook1: mov ah,getintv ; get interrupt vector
mov al,8 ; vector number
int dos
mov ax,es
mov cx,cs
cmp ax,cx ; points to us now?
je hook2 ; e = yes, do not touch
mov word ptr DGROUP:oldint8+2,ax ; save segment
mov word ptr DGROUP:oldint8,bx ; save offset
mov dx,offset ourtimer ; new handler
push ds
mov ax,cs ; segment
mov ds,ax
mov al,8 ; for Int 8
mov ah,25H ; set interrupt address from ds:dx
int dos
pop ds
hook2: mov tcpflag,1 ; say Kermit but not Int 8 is running TCP
mov ax,1 ; return 1 for success
pop es
pop bp
ret
hook3: call unhookvect ; put any back
xor ax,ax ; return 0 for failure
pop es
pop bp
ret
hookvect endp
public _unhookvect
unhookvect proc near
_unhookvect equ this byte
push bp
mov bp,sp
push es
push bx
push cx
clc
mov tempax,0 ; assume failure status
mov ah,getintv ; get interrupt vector
mov al,14h ; vector number
int dos
jc unhook1 ; c = failed
mov ax,es ; es:bx is current owner, us?
mov cx,cs
cmp ax,cx ; seg should be right here
jne unhook1 ; ne = is not
cmp bx,offset ourserial ; should be the same too
jne unhook1 ; ne = is not, let them have the int
mov ax,word ptr DGROUP:oldint14+2 ; segment
mov dx,word ptr DGROUP:oldint14 ; offset
mov cx,dx
or cx,ax ; was it used by us?
jz unhook1 ; z = no, leave alone
push ds
mov ds,ax
mov al,14h ; for Int 14h
mov ah,25H ; set interrupt address from ds:dx
int dos
pop ds
mov word ptr DGROUP:oldint14,0
mov word ptr DGROUP:oldint14+2,0
mov tempax,1 ; success so far
unhook1:mov ah,getintv ; get interrupt vector
clc
mov al,8 ; vector number
int dos
jc unhook2 ; c = failed
mov ax,es ; es:bx is current owner, us?
mov cx,cs
cmp ax,cx ; seg should be right here
jne unhook2 ; ne = is not
cmp bx,offset ourtimer ; should be the same too
jne unhook2 ; ne = is not, let them have the int
mov ax,word ptr DGROUP:oldint8+2 ; segment
mov dx,word ptr DGROUP:oldint8 ; offset
mov cx,dx
or cx,ax ; was it used by us?
jz unhook2 ; z = no, leave alone
push ds
mov ds,ax
mov al,8 ; for Int 8
mov ah,25H ; set interrupt address from ds:dx
int dos
pop ds
and tcpflag,not 2 ; Int 8 no longer touches TCP
mov word ptr DGROUP:oldint8,0
mov word ptr DGROUP:oldint8+2,0
mov tempax,1 ; success status
jmp short unhook3
unhook2:mov tempax,0 ; failure
unhook3:mov ax,tempax ; return status (1=success, 0=fail)
pop cx
pop bx
pop es
pop bp
ret
unhookvect endp
; Int 8 routine to call the TCP code if Kermit does not.
ourtimer proc near
push ds
push ax
mov ax,dgroup ; set addressibility to our dgroup
mov ds,ax
pushf ; simulate interrupt invokation
call dword ptr DGROUP:oldint8 ; call previous owner of Int 8
mov ax,dgroup
mov ds,ax
test tcpflag,1+2 ; is TCP code running now?
jnz ourtim2 ; nz = yes, so we don't run now
mov al,int8cnt ; get our times called counter
inc al ; up once again
and al,7 ; keep 3 bits, about .5 sec @18.2tic/s
mov int8cnt,al ; store
or al,al ; is it zero?
jnz ourtim2 ; nz = no, go away for awhile
or tcpflag,2 ; say we are running the TCP code
push bp
push bx
push cx
push dx
push si
push di
push es
mov ax,dgroup ; set addressibility to our dgroup
mov ds,ax
cli
mov ax,ss
mov word ptr stack8+2,ax ; save current stack
mov word ptr stack8,sp
mov ax,word ptr tcpstack+2 ; get TCP stack seg
mov ss,ax ; set to TCP stack
mov sp,word ptr tcpstack
sti ; restart interrupts
call _int8tick ; read some packets
mov ax,word ptr stack8+2 ; get original stack seg
cli
mov ss,ax
mov sp,word ptr stack8
sti
pop es
pop di
pop si
pop dx
pop cx
pop bx
pop bp
and tcpflag,not 2 ; finished our running of TCP code
ourtim2:pop ax
pop ds
iret
ourtimer endp
; This routine is invoked from outside by Int 14h. Enter with the caller's
; registers but our CS. Switch stacks and data segments.
; This version supports 3Com BAPI calls and does the near/far stuff via
; a local buffer.
ourserial proc near ; Interrupt 14h service routine
assume ds:DGROUP
push ds
push ax
mov ax,dgroup ; set addressibility to our dgroup
mov ds,ax
pop ax
test tcpflag,2 ; is Int 8 running TCP?
jz ourser8 ; z = no
mov ah,1 ; say no char written
xor cx,cx ; chars written
pop ds
iret
ourser8:or tcpflag,1 ; say we are running TCP
push es ; save regs on the user's stack
push di
push si
push dx
push bx
push bp
push ax
mov ax,dgroup ; set addressibility to our dgroup
mov ds,ax
pop ax
mov kstack,sp ; remember caller's stack now
mov sp,word ptr tcpstack ; move to our TCP stack
mov word ptr userbuf,bx ; remember caller's es:bx
mov word ptr userbuf+2,es
mov _bapireq,cx ; requested char count to TCP code
mov _bapiret,0 ; init returned CX char count
mov opcode,ah ; remember operation for return proc
cmp ah,bapihere ; presence check?
jne ourser6 ; ne = no
mov ax,0af01h ; return this value
jmp ourser4 ; done
ourser6:
cmp ah,bapiwrit ; BAPI write?
jne ourser2 ; ne = no
push ax
push cx
push es
push ds
mov di,offset DGROUP:_bapibuf ; where it goes
mov si,bx ; es:bx, whence it comes
mov bx,es
mov ax,ds
mov es,ax
mov ds,bx
cld
cmp cx,buflen ; largest block i/o we allow here
jbe ourser1 ; be = ok
mov cx,buflen ; truncate the request
ourser1:shr cx,1
jnc ourser1a
movsb
ourser1a:rep movsw ; copy their buffer to ours
pop ds
pop es
pop cx
pop ax
ourser2:cmp ah,bapiread ; read?
jne ourser3 ; ne = no
cmp _msgcnt,0 ; any outstanding msgs from TCP?
je ourser3 ; e = no msgs
call oursmsg ; send back the msgs instead
jmp short ourser4 ; ax has status of ok
ourser3:sti ; let other ints happen
mov bx,dgroup ; set up es to dgroup too
mov es,bx ; bx is not needed at this time
xchg ah,al ; put function code in al
xor ah,ah
push ax ; setup call frame
call _int14handler ; a near call, _int14handler(ax)
cli ; reg ax has return status
add sp,2 ; clean stack
mov cx,dgroup ; safety check, not really needed
mov ds,cx
mov cx,_bapiret ; count of chars returned
cmp opcode,bapiread ; BAPI read?
jne ourser4 ; ne = no
jcxz ourser4 ; z = nothing to copy
push ax
push cx
mov si,offset DGROUP:_bapibuf ; whence it comes
mov di,word ptr userbuf ; where it goes
mov ax,word ptr userbuf+2 ; segment
mov es,ax
cld
shr cx,1
jnc ourser3a
movsb
ourser3a:rep movsw ; copy our buffer to theirs
pop cx ; return count in cx
pop ax ; return result code in ah, cnt in cx
ourser4:clc ; assume success
xchg ah,al ; put return status in ah
xor al,al
cmp ah,3 ; serious error status?
jb ourserx ; b = no, zero is success
stc ; set carry too
ourserx:mov sp,kstack ; move to caller's stack
and tcpflag,not 1 ; say we are not running TCP
pop bp
pop bx
pop dx
pop si
pop di
pop es
pop ds
iret ; AX and CX are changed as returns
ourserial endp
oursmsg proc near
mov cx,_msgcnt
jcxz ourser3 ; z = no msgs
cmp cx,_bapireq ; longer than request?
jbe oursmsg1 ; be = no
mov cx,_bapireq ; do this much now
oursmsg1:push cx
mov si,offset DGROUP:_msgbuf ; whence it comes
mov di,word ptr userbuf ; where it goes
mov ax,word ptr userbuf+2 ; segment
mov es,ax
cld
rep movsb ; copy our buffer to theirs
pop cx ; return count in cx
mov _bapiret,cx ; return count to user
sub _msgcnt,cx ; deduct chars relayed
cmp _msgcnt,0 ; examine remainder
je oursmsg3 ; e = none
mov ax,_msgcnt ; count
push ax
mov ax,offset DGROUP:_msgbuf
push ax ; destination
add ax,_msgcnt ; source
push ax
call _bcopy ; copy to beginning of buffer
add sp,6 ; clean stack
oursmsg3:mov ax,0 ; return status of success
ret
oursmsg endp
; tcpaddress db '127.0.0.1',(32-($-tcpaddress)) dup (0),0
; tcpsubnet db '255.255.255.0',(32-($-tcpsubnet)) dup (0),0
; tcpdomain db 'loopback',(32-($-tcpdomain)) dup (0),0
; tcpgateway db '127.0.0.1',(32-($-tcpgateway)) dup (0),0
; tcpprimens db '127.0.0.1',(32-($-tcpprimens)) dup (0),0
; tcpsecondns db '127.0.0.1',(32-($-tcpsecondns)) dup (0),0
; tcphost db (32-($-tcphost)) dup (0),0
; tcpbcast db 0ffh
;
; tcpdata dw offset tcpaddress ; externally visible far pointers
; dw offset tcpsubnet
; dw offset tcpdomain
; dw offset tcpgateway
; dw offset tcpprimens
; dw offset tcpsecondns
; dw offset tcphost
; dw offset tcpbcast
public ktcpstart
ktcpstart proc far
ASSUME DS:DATA, ES:DGROUP
push es ; save regs on main Kermit stack
push ds
push di
push si
push dx
push cx
push bx
push bp
mov ax,DGROUP
mov es,ax ; destination is the TCP module
cld
mov tcpdata,bx ; store offset of Kermit data block
mov si,[bx] ; get offset of our IP address
mov di,offset DGROUP:_kmyip ; our storage slot
mov cx,16 ; max bytes
start5: lodsb
stosb
or al,al
loopne start5 ; copy IP address string, asciiz
xor al,al ; extra terminator
stosb
mov si,[bx+2] ; get offset in Kermit
mov di,offset DGROUP:_knetmask
mov cx,16
start6: lodsb
stosb
or al,al
loopne start6
xor al,al
stosb
mov si,[bx+4] ; get offset in Kermit
mov di,offset DGROUP:_kdomain
mov cx,32
start7: lodsb
stosb
or al,al
loopne start7
xor al,al
stosb
mov si,[bx+6] ; get offset in Kermit
mov di,offset DGROUP:_kgateway
mov cx,32
start8: lodsb
stosb
or al,al
loopne start8
xor al,al
stosb
mov si,[bx+8] ; get offset in Kermit
mov di,offset DGROUP:_kns1
mov cx,32
start9: lodsb
stosb
or al,al
loopne start9
xor al,al
stosb
mov si,[bx+10] ; get offset in Kermit
mov di,offset DGROUP:_kns2
mov cx,32
start10:lodsb
stosb
or al,al
loopne start10
xor al,al
stosb
mov si,[bx+12] ; get offset in Kermit
mov di,offset DGROUP:_khost
mov cx,32
start11:lodsb
stosb
or al,al
loopne start11
xor al,al
stosb
mov si,[bx+14] ; broadcast byte address
mov di,offset DGROUP:_kbcast
mov cx,32
start12:lodsb
stosb
or al,al
loopne start12
xor al,al
stosb
mov es:_display_mode,0 ; presume quiet screen
test flags.remflg,dquiet ; quiet display mode?
jnz start13 ; nz = yes. Don't write to screen
inc es:_display_mode ; say can write to screen
start13:mov bx,tcptos ; top of stack for tcp code
assume ds:DGROUP, ES:NOTHING
mov ax,dgroup ; set addressibility to our dgroup
mov ds,ax
mov es,ax
mov word ptr tcpstack+2,ax ; set TCP stack seg
mov word ptr kstack,sp ; store Kermit's stack ptr
mov sp,bx ; new TCP stack pointer, DGROUP based
mov bp,sp ; preset this as insurance
or tcpflag,1 ; say this is running TCP code
call _main ; call the C code
and tcpflag,not 1 ; finished running tcp code
mov sp,word ptr kstack ; restore for Kermit's main stack
pop bp ; restore regs, Kermit's main stack
pop bx
pop cx
pop dx
pop si
pop di
pop ds
pop es
ret ; return to caller
ktcpstart endp
public ktcpstop
ktcpstop proc far
assume ds:dgroup, es:nothing
push es ; save regs on the user's stack
push ds
push di
push si
push dx
push cx
push bx
push bp
mov ax,dgroup ; set addressibility to our dgroup
mov ds,ax
mov kstack,sp ; remember Kermit's main sp
or tcpflag,1 ; say we are running TCP code
mov ax,word ptr tcpstack ; set sp to TCP sp
mov sp,ax
mov bp,sp ; preset this as insurance
push ds
pop es
xor ax,ax
push ax ; exit(0) setup
call _exit
add sp,2 ; returns status in AX
mov tempax,ax
mov ax,word ptr tcpstack ; set sp to TCP sp again
mov sp,ax
mov bp,sp ; preset this as insurance
call _pkt_release ; do this as insurance
mov ax,tempax ; regain status
push ax
call unhookvect ; ditto
pop ax
mov tcpflag,0 ; no one is running the TCP code
mov sp,kstack
pop bp ; restore regs, Kermit's main stack
pop bx
pop cx
pop dx
pop si
pop di
pop ds
pop es
ret ; return to caller
ktcpstop endp
public _readback
_readback proc near
assume ds:dgroup, es:dgroup
push bp
mov bp,sp
push si
push di
push es
mov ax,data
mov es,ax
mov si,offset dgroup:_kmyip
push si
push si
call _strlen ; get length of string
add sp,2
pop si
mov di,tcpdata ; copy to Kermit main body
mov di,es:[di] ; offset of the string
mov cx,ax
cld
rep movsb
xor al,al
stosb ; terminator
mov si,offset dgroup:_knetmask
mov di,tcpdata
mov di,es:[di+2]
mov cx,17
rep movsb
stosb ; terminator
mov si,offset dgroup:_kgateway
mov di,tcpdata
mov di,es:[di+6]
mov cx,17
rep movsb
stosb ; terminator
mov si,offset dgroup:_kns1
mov di,tcpdata
mov di,es:[di+8]
mov cx,17
rep movsb
stosb ; terminator
mov si,offset dgroup:_kns2
mov di,tcpdata
mov di,es:[di+10]
mov cx,17
rep movsb
stosb ; terminator
pop es
pop si
pop di
pop bp
ret
_readback endp
; Track Telnet echo variable (0 do not do local echo) into terminal emulator
; and Kermit main body. Call this each time Telnet options change echo.
public _kecho
_kecho proc near
assume ds:data, es:dgroup
push bp
mov bp,sp
push ds
push es
push si
push ax
mov ax,data ; Kermit main data segment
mov ds,ax
mov ax,dgroup
mov es,ax
mov ax,[bp+4+0] ; get Telnet _echo variable
and yflags,not lclecho ; assume no local echo in emulator
or al,al ; Telnet local echo is off?
jz kecho1 ; z = yes
mov al,lclecho ; lclecho flag for emulator
kecho1: or yflags,al ; set terminal emulator
mov si,portval
mov [si].ecoflg,al ; set mainline SET echo flag
pop ax
pop si
pop es
pop ds
pop bp
ret
_kecho endp
_TEXT ends
end